#ifndef MAIN_THREAD_H
#define MAIN_THREAD_H

#include <QObject>
#include <QThread>
#include <QDebug>
#include <QJsonObject>
#include <QJsonValue>
#include <windows.h>
#include <winbase.h>
extern "C"{
#include <hidsdi.h>
#include <devguid.h>
}
#include <setupapi.h>

#include "GetHIDDevice.h"

#define FileName "setting.ini"
typedef struct
{
    uint8_t reprotid;
    uint8_t HatSwitch;
    uint16_t Buttons;
    uint16_t Axis_Rx;
    uint16_t Axis_Ry;
    uint16_t Axis_X;
    uint16_t Axis_Y;
    int16_t Wheel;
    uint16_t Throttle;
    uint16_t Brake;
} reprot_type;

typedef struct{
    uint8_t reprotid;
    uint8_t dead_Rx_Low;
    uint8_t dead_Rx_High;
    uint8_t dead_Ry_Low;
    uint8_t dead_Ry_High;
    uint8_t dead_Brake_Low;
    uint8_t dead_Brake_High;
    uint8_t dead_Throttle_Low;
    uint8_t dead_Throttle_High;
    uint8_t wave_filtering;
    union {
        struct
        {
            uint8_t ENABLE_Rx:1;
            uint8_t ENABLE_Ry:1;
            uint8_t ENABLE_Brake:1;
            uint8_t ENABLE_Throttle:1;
            uint8_t MODE_1:1;
            uint8_t MODE_2:1;
            uint8_t MODE_3:1;
            uint8_t MODE_4:1;
        };
        struct
        {
            uint8_t ENABLE_Flags:4;
            uint8_t MODE_Flags:4;
        };
        uint8_t Flags;
    };
    uint8_t temp;
}Out_Reprot_Type;

typedef struct {
    uint8_t reportid;
    uint8_t Wheel_Flag;
    uint8_t Force;
    uint8_t Friction;
    uint8_t Gain;
    uint8_t temp;
    int16_t Wheel_Engle;
    uint16_t Wheel_EncoderCPR;
    uint16_t Wheel_Degrees;
}Wheel_config;

extern HID_Device hiddevice;
class Main_Thread : public QThread
{
    Q_OBJECT
    Q_PROPERTY(QJsonObject Data READ getData WRITE setData NOTIFY dataChanged)
    Q_PROPERTY(QJsonObject Config READ getConfig WRITE setConfig NOTIFY configChanged)
    Out_Reprot_Type out_reprot;
    Wheel_config wheel_config;
    reprot_type reprot;
    int setting_flag = 0;
public:
    char SavaPath[128] = {0};
    Main_Thread(){
        GetModuleFileNameA(NULL,SavaPath,128);
        (strrchr(SavaPath,'\\'))[1] = 0;
        strcat(SavaPath,FileName);
        out_reprot.reprotid = 0x0d;
        wheel_config.reportid = 0x0e;
        reprot.reprotid = 0x01;
        ReadConfig(&out_reprot,&wheel_config);
    };
    ~Main_Thread(){
        SavaConfig(&out_reprot,&wheel_config);
        Run_flag = 0;
    }
    void run(){
        qDebug() << "Thread Running !";
        BOOL Result;
        hiddevice.VID = 0x1a86;
        ReadConfig(&out_reprot,&wheel_config);
        FindHidDevice(&hiddevice);
        if(hiddevice.PID == 0xe6e1){
            emit startflag(1);
        }else{
            emit startflag(0);
            Run_flag = 0;
            return;
        }
        DWORD len = 0;
        while(Run_flag){
            Result = ReadFile(hiddevice.Device,&reprot,18,&len,0);
            if(Result == FALSE){
                len = GetLastError();
                qDebug() << "ReadFile Error:" <<len;
                emit startflag(0);
                Run_flag = 0;
                return;
            }
            Json.insert("Wheel",reprot.Wheel);
            Json.insert("Rx",reprot.Axis_Rx);
            Json.insert("Ry",reprot.Axis_Ry);
            Json.insert("Brake",reprot.Brake);
            Json.insert("Throttle",reprot.Throttle);
            setData(Json);
            if(setting_flag){
                Result = WriteFile(hiddevice.Device,&out_reprot,12,&len,0);
                //                qDebug()<< "out:" << out_reprot.ENABLE_Brake << out_reprot.dead_Brake_Low << out_reprot.wave_filtering << out_reprot.MODE_1 << out_reprot.dead_Throttle_High;
                //                qDebug() << "flags:" << out_reprot.ENABLE_Flags << out_reprot.MODE_Flags <<out_reprot.Flags;
                //            qDebug() << "Send Size:" << len;
                if(Result == FALSE){
                    len = GetLastError();
                    emit startflag(0);
                    Run_flag = 0;
                    qDebug() << "WriteFile Error:" <<len;
                }
                if(out_reprot.temp != 0){
                    SavaConfig(&out_reprot,&wheel_config);
                    out_reprot.temp = 0;
                }
                setting_flag = 0;
            }
            if(Wheel_Flag){
                Result = WriteFile(hiddevice.Device,&wheel_config,12,&len,0);
                //                qDebug()<< "out:" << out_reprot.ENABLE_Brake << out_reprot.dead_Brake_Low << out_reprot.wave_filtering << out_reprot.MODE_1 << out_reprot.dead_Throttle_High;
                //                qDebug() << "flags:" << out_reprot.ENABLE_Flags << out_reprot.MODE_Flags <<out_reprot.Flags;
                //            qDebug() << "Send Size:" << len;
                if(Result == FALSE){
                    len = GetLastError();
                    Run_flag = 0;
                    qDebug() << "WriteFile Error:" <<len;
                }
                wheel_config.Wheel_Flag = 0;
                Wheel_Flag = 0;
            }
        }
        emit startflag(0);
    }
    Q_INVOKABLE QJsonObject getData() const {return Json;}
    Q_INVOKABLE void setFlag(int Flag){
        Run_flag = Flag;
    }

    void SavaConfig(Out_Reprot_Type* reprot,Wheel_config* config){
        char temp[10];
        sprintf(temp, "%d", reprot->reprotid);
        WritePrivateProfileStringA("Control","reprotid",temp,SavaPath);
        sprintf(temp, "%d",reprot->dead_Brake_High);
        WritePrivateProfileStringA("Control","dead_Brake_High",temp,SavaPath);
        sprintf(temp, "%d",reprot->dead_Brake_Low);
        WritePrivateProfileStringA("Control","dead_Brake_Low",temp,SavaPath);
        sprintf(temp, "%d",reprot->dead_Throttle_High);
        WritePrivateProfileStringA("Control","dead_Throttle_High",temp,SavaPath);
        sprintf(temp, "%d",reprot->dead_Throttle_Low);
        WritePrivateProfileStringA("Control","dead_Throttle_Low",temp,SavaPath);
        sprintf(temp, "%d",reprot->dead_Rx_High);
        WritePrivateProfileStringA("Control","dead_Rx_High",temp,SavaPath);
        sprintf(temp, "%d",reprot->dead_Rx_Low);
        WritePrivateProfileStringA("Control","dead_Rx_Low",temp,SavaPath);
        sprintf(temp, "%d",reprot->dead_Ry_High);
        WritePrivateProfileStringA("Control","dead_Ry_High",temp,SavaPath);
        sprintf(temp, "%d",reprot->dead_Ry_Low);
        WritePrivateProfileStringA("Control","dead_Ry_Low",temp,SavaPath);
        sprintf(temp, "%d",reprot->wave_filtering);
        WritePrivateProfileStringA("Control","wave_filtering",temp,SavaPath);
        sprintf(temp, "%d",reprot->Flags);
        WritePrivateProfileStringA("Control","Flags",temp,SavaPath);

        sprintf(temp, "%d",config->Wheel_EncoderCPR);
        WritePrivateProfileStringA("Wheel","EncoderCPR",temp,SavaPath);
        sprintf(temp, "%d",config->Wheel_Degrees);
        WritePrivateProfileStringA("Wheel","Degrees",temp,SavaPath);
        sprintf(temp, "%d",config->Force);
        WritePrivateProfileStringA("Wheel","Force",temp,SavaPath);
        sprintf(temp, "%d",config->Gain);
        WritePrivateProfileStringA("Wheel","Gain",temp,SavaPath);
        sprintf(temp, "%d",config->Friction);
        WritePrivateProfileStringA("Wheel","Friction",temp,SavaPath);
    }

    void ReadConfig(Out_Reprot_Type* reprot,Wheel_config* wheel_config){
        char temp[10];
        QJsonObject config;
        GetPrivateProfileStringA("Control","reprotid","13",temp,10,SavaPath);
        reprot->reprotid = atoi(temp);
        config.insert("reprotid",temp);
        GetPrivateProfileStringA("Control","dead_Brake_High","100",temp,10,SavaPath);
        reprot->dead_Brake_High = atoi(temp);
        config.insert("dead_Brake_High",temp);
        GetPrivateProfileStringA("Control","dead_Brake_Low","0",temp,10,SavaPath);
        reprot->dead_Brake_Low = atoi(temp);
        config.insert("dead_Brake_Low",temp);
        GetPrivateProfileStringA("Control","dead_Throttle_High","100",temp,10,SavaPath);
        reprot->dead_Throttle_High = atoi(temp);
        config.insert("dead_Throttle_High",temp);
        GetPrivateProfileStringA("Control","dead_Throttle_Low","0",temp,10,SavaPath);
        reprot->dead_Throttle_Low = atoi(temp);
        config.insert("dead_Throttle_Low",temp);
        GetPrivateProfileStringA("Control","dead_Rx_High","100",temp,10,SavaPath);
        reprot->dead_Rx_High = atoi(temp);
        config.insert("dead_Rx_High",temp);
        GetPrivateProfileStringA("Control","dead_Rx_Low","0",temp,10,SavaPath);
        reprot->dead_Rx_Low = atoi(temp);
        config.insert("dead_Rx_Low",temp);
        GetPrivateProfileStringA("Control","dead_Ry_High","100",temp,10,SavaPath);
        reprot->dead_Ry_High = atoi(temp);
        config.insert("dead_Ry_High",temp);
        GetPrivateProfileStringA("Control","dead_Ry_Low","0",temp,10,SavaPath);
        reprot->dead_Ry_Low = atoi(temp);
        config.insert("dead_Ry_Low",temp);
        GetPrivateProfileStringA("Control","wave_filtering","35",temp,10,SavaPath);
        reprot->wave_filtering = atoi(temp);
        config.insert("wave_filtering",temp);
        GetPrivateProfileStringA("Control","Flags","31",temp,10,SavaPath);
        reprot->Flags = atoi(temp);
        config.insert("Flags",temp);

        GetPrivateProfileStringA("Wheel","EncoderCPR","10000",temp,10,SavaPath);
        wheel_config->Wheel_EncoderCPR = atoi(temp);
        config.insert("EncoderCPR",temp);
        GetPrivateProfileStringA("Wheel","Degrees","360",temp,10,SavaPath);
        wheel_config->Wheel_Degrees = atoi(temp);
        config.insert("Degrees",temp);
        GetPrivateProfileStringA("Wheel","Force","50",temp,10,SavaPath);
        wheel_config->Force = atoi(temp);
        config.insert("Force",temp);
        GetPrivateProfileStringA("Wheel","Gain","0",temp,10,SavaPath);
        wheel_config->Gain = atoi(temp);
        config.insert("Gain",temp);
        GetPrivateProfileStringA("Wheel","Friction","0",temp,10,SavaPath);
        wheel_config->Friction = atoi(temp);
        config.insert("Friction",temp);
        //        qDebug() << temp;
        setConfig(config);
    }

    Q_INVOKABLE void f_TesT(){
        ReadConfig(&out_reprot,&wheel_config);
    }

    Q_INVOKABLE void setReprot(QJsonObject reprot,uint8_t flag){
        setting_flag = 1;
        if(flag == 1){
            if(reprot.contains("MODE_1")){
                out_reprot.MODE_Flags = reprot.value("MODE_1").toInt();
            }
            if(reprot.contains("MODE_2")){
                out_reprot.MODE_Flags = reprot.value("MODE_2").toInt();
            }
            if(reprot.contains("MODE_3")){
                out_reprot.MODE_Flags = reprot.value("MODE_3").toInt();
            }
            if(reprot.contains("MODE_4")){
                out_reprot.MODE_Flags = reprot.value("MODE_4").toInt();
            }
        }
        if(flag == 2){
            if(reprot.contains("ENABLE_Rx")){
                out_reprot.ENABLE_Rx = reprot.value("ENABLE_Rx").toInt();
            }
            if(reprot.contains("ENABLE_Ry")){
                out_reprot.ENABLE_Ry = reprot.value("ENABLE_Ry").toInt();
            }
            if(reprot.contains("ENABLE_Brake")){
                out_reprot.ENABLE_Brake = reprot.value("ENABLE_Brake").toInt();
            }
            if(reprot.contains("ENABLE_Throttle")){
                out_reprot.ENABLE_Throttle = reprot.value("ENABLE_Throttle").toInt();
            }
            //            qDebug() << "flags: " <<out_reprot.ENABLE_Flags ;
        }
        if(flag == 4){


            if(reprot.contains("dead_Rx_Low")){
                out_reprot.dead_Rx_Low = (uint8_t)reprot.value("dead_Rx_Low").toDouble();
            }
            if(reprot.contains("dead_Ry_Low")){
                out_reprot.dead_Ry_Low = (uint8_t)reprot.value("dead_Ry_Low").toDouble();
            }
            if(reprot.contains("dead_Brake_Low")){
                out_reprot.dead_Brake_Low = (uint8_t)reprot.value("dead_Brake_Low").toDouble();
            }
            if(reprot.contains("dead_Throttle_Low")){
                out_reprot.dead_Throttle_Low = (uint8_t)reprot.value("dead_Throttle_Low").toDouble();
            }

            if(reprot.contains("dead_Rx_High")){
                out_reprot.dead_Rx_High = (uint8_t)reprot.value("dead_Rx_High").toDouble();
            }
            if(reprot.contains("dead_Ry_High")){
                out_reprot.dead_Ry_High = (uint8_t)reprot.value("dead_Ry_High").toDouble();
            }
            if(reprot.contains("dead_Brake_High")){
                out_reprot.dead_Brake_High = (uint8_t)reprot.value("dead_Brake_High").toDouble();
            }
            if(reprot.contains("dead_Throttle_High")){
                out_reprot.dead_Throttle_High = (uint8_t)reprot.value("dead_Throttle_High").toDouble();
            }
        }
        if(flag == 8){
            if(reprot.contains("wave_filtering")){
                out_reprot.wave_filtering = reprot.value("wave_filtering").toInt();
            }
        }
        if(flag == 16){
            if(reprot.contains("temp")){
                out_reprot.temp = reprot.value("temp").toInt();
            }
        }

    }

    Q_INVOKABLE void setWheel_Force(uint8_t value){
        wheel_config.Force = value;
        Wheel_Flag = 1;
        qDebug() << "Force: " << wheel_config.Force;
    }
    Q_INVOKABLE void setWheel_Gain(uint8_t value){
        wheel_config.Gain = value;
        Wheel_Flag = 1;
        qDebug() << "Gain: " << wheel_config.Gain;
    }
    Q_INVOKABLE void setWheel_Friction(uint8_t value){
        wheel_config.Friction = value;
        Wheel_Flag = 1;
        qDebug() << "Friction: " << wheel_config.Friction;
    }
    Q_INVOKABLE void start_Calibration(){
        wheel_config.Wheel_Flag = 0x44;
        Wheel_Flag = 1;
        qDebug() << "start_Calibration: ";
    }
    Q_INVOKABLE void setWheel_EncoderCPR(uint16_t value){
        if(!(value < 2000)){
            wheel_config.Wheel_EncoderCPR = value;
            Wheel_Flag = 1;
        }
        qDebug() << "Encoder: " << wheel_config.Wheel_EncoderCPR;
    }
    Q_INVOKABLE void setWheel_Engle(int16_t value){
        wheel_config.Wheel_Engle = value;
        wheel_config.Wheel_Flag = 0x01;
        Wheel_Flag = 1;
        qDebug() << "Wheel_Engle: " << wheel_config.Wheel_Engle;
    }
    Q_INVOKABLE void setWheel_Degrees(int16_t value){

        if(!(value < 180)){
            wheel_config.Wheel_Degrees = value;
            Wheel_Flag = 1;
        }
        qDebug() << "Wheel_Degrees: " << wheel_config.Wheel_Degrees;
    }

    Q_INVOKABLE QJsonObject getConfig(){
        return config;
    }

signals:
    void dataChanged(QJsonObject Json);
    void configChanged(QJsonObject Json);
    void wheel_engleChanged(int16_t value);
    void wheel_configChanged(QJsonObject Json);
    void startflag(int i);
public slots:
    void setData(QJsonObject Json){
        emit dataChanged( Json );
    }
    void setConfig(QJsonObject config){
        emit configChanged(config);
    }
private:
    int Run_flag = 1;
    uint8_t Wheel_Flag;
    QJsonObject config;
    QJsonObject Json;
};

#endif // MAIN_THREAD_H
